/**
 * @file implements Custom Progress Bar
 * @author CORSAIR <vladimir.corsair@gmail.com>
 * @version 1.7.0
 */
var CustomProgressBar = function() {
    this.progressCallbacks = [];
    this.completeCallbacks = [];
    this.completeCallbacksAF = [];
    this.pgID = "body-";
    this.pgaID = "arrow-";
    this.animationProgressInterval = null;
    this.animationProgressOpacityInterval = null;
    this.animationInProgress = null;
};

CustomProgressBar.prototype.init = function(max, opts) {
    var s = opts || {};
    this.arrowSpeed = s.arrowSpeed || 100;
    this.fadeOutSpeed = s.fadeOutSpeed || 300;
    this.current = 0;
    this.lastCurrent = 0;
    this.max = Math.floor(max);
    this.body = document.createElement('div');
    this.body.setAttribute("style", "");
    this.body.setAttribute("id", this.pgID);
    var bodyStyle = {
        width: this.toPx(this.windowWidth()),
        height: s.bodyHeight || s.bodyHeight === 0 ? this.toPx(s.bodyHeight) : this.toPx(3),
        position: "fixed",
        top: this.toPx(0),
        left: this.toPx(0),
        backgroundColor: s.bodyColor || "transparent",
        opacity: 1,
        "z-index": 11
    };
    for (var x in bodyStyle) {
        this.body.style[x] = bodyStyle[x];
    }
    this.arrow = document.createElement('div');
    this.arrow.setAttribute("style", "");
    this.arrow.setAttribute("id", this.pgaID);
    var arrowStyle = {
        width: this.toPx(0),
        height: s.arrowHeight ? this.toPx(s.arrowHeight) : this.toPx(3),
        position: "fixed",
        top: this.toPx(0),
        left: this.toPx(0),
        backgroundColor: s.arrowColor || "#3CB371",
        "z-index": 2
    };
    for (var x in arrowStyle) {
        this.arrow.style[x] = arrowStyle[x];
    }
    this.arrow.style[this.getSupportedProp(['boxShadow', 'MozBoxShadow', 'WebkitBoxShadow'])] = "3px -1px 10px 0px " + arrowStyle.backgroundColor;
    this.body.appendChild(this.arrow);
    document.getElementsByTagName('body')[0].appendChild(this.body);
    clearInterval(this.waitInterval);
    this.wait();
    window.onresize = (function() {
        this.body.style.width = this.toPx(this.windowWidth());
        this.reanimateArrow(1);
    }).bind(this);
};

CustomProgressBar.prototype.windowWidth = function() {
    return window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
};
CustomProgressBar.prototype.toPx = function(num) {
    return parseFloat(num).toString() + "px";
};
CustomProgressBar.prototype.calculateArrowWidth = function() {
    return this.windowWidth() * (this.getPercents() / 100);
};
CustomProgressBar.prototype.getCurrentWidth = function() {
    return parseFloat(this.arrow.style.width);
};
CustomProgressBar.prototype.setCurrentWidth = function(n) {
    return this.arrow.style.width = this.toPx(n);
};
CustomProgressBar.prototype.getPercents = function() {
    return (this.current / this.max) * 100;
};
CustomProgressBar.prototype.getCurrentOpacity = function() {
    return parseFloat(this.body.style.opacity);
};
CustomProgressBar.prototype.setCurrentOpacity = function(n) {
    return this.body.style.opacity = n;
};
CustomProgressBar.prototype.fadeOut = function(c) {
    var speed = this.fadeOutSpeed;
    var speedStep = speed;
    var step = 1 / speed;
    this.animationProgressOpacityInterval = setInterval((function() {
        speedStep--;
        if (speedStep <= 0) {
            clearInterval(this.animationProgressOpacityInterval);
            this.setDefault();
            c.call(this) || (function() {
            })();
        }
        this.setCurrentOpacity(this.getCurrentOpacity() - step);
    }).bind(this), 1);
};
CustomProgressBar.prototype.setDefault = function() {
    this.current = 0;
    this.lastCurrent = 0;
    this.max = 0;
    this.animationProgressInterval = null;
    this.animationProgressOpacityInterval = null;
    this.waitInterval = null;
    document.getElementById(this.pgID).remove();
};
CustomProgressBar.prototype.reanimateArrow = function(s) {
    this.animationInProgress = true;
    var currentWidth = this.getCurrentWidth();
    var finalWidth = this.calculateArrowWidth();
    var speed = this.arrowSpeed;
    var speedStep = speed;
    var step = finalWidth - currentWidth;
    if (this.animationProgressInterval) {
        clearInterval(this.animationProgressInterval);
    }
    this.animationProgressInterval = setInterval((function() {
        speedStep = speedStep - 1;
        if (speedStep <= 0) {
            clearInterval(this.animationProgressInterval);
            this.animationInProgress = false;
        }
        this.setCurrentWidth(this.getCurrentWidth() + (step / speed));
    }).bind(this), 1);
};
CustomProgressBar.prototype.wait = function() {
    this.waitInterval = setInterval((function() {
        if (this.lastCurrent !== this.current) {
            this.lastCurrent = this.current;
            this.reanimateArrow();
            for (var x in this.progressCallbacks) {
                this.progressCallbacks[x].call(this, this.getPercents());
            }
        }
        if (this.current >= this.max && !this.animationInProgress) {
            clearInterval(this.waitInterval);
            for (var x in this.completeCallbacks) {
                this.completeCallbacks[x].call(this);
            }
            this.fadeOut(function() {
                for (var x in this.completeCallbacksAF) {
                    this.completeCallbacksAF[x].call(this);
                }
            });
        }
    }).bind(this), 10);
};
CustomProgressBar.prototype.update = function(newCurrent) {
    newCurrent = parseInt(newCurrent) || newCurrent;
    this.current = newCurrent > this.max ? this.max : newCurrent;
};
CustomProgressBar.prototype.onUpdate = function(callb) {
    this.progressCallbacks.push(callb);
};
CustomProgressBar.prototype.onComplete = function(callb) {
    this.completeCallbacks.push(callb);
};
CustomProgressBar.prototype.onFadeComplete = function(callb) {
    this.completeCallbacksAF.push(callb);
};
CustomProgressBar.prototype.getSupportedProp = function(p) {
    var root = document.documentElement;
    for (var i = 0; i < p.length; i++) {
        if (typeof root.style[p[i]] === "string") {
            return p[i];
        }
    }
};

CustomProgressBar.remove = function () {
    this.parentElement.removeChild(this);
};

if(typeof HTMLElement !== "undefined") {
    HTMLElement.prototype.remove = CustomProgressBar.remove;
}
if(typeof Element !== "undefined") {
    Element.prototype.remove = CustomProgressBar.remove;
}